package com.jyy.utils.dynamicdatasource.aspect;

import com.jyy.utils.dynamicdatasource.DynamicConstant;
import com.jyy.utils.dynamicdatasource.DynamicProperties;
import com.jyy.utils.dynamicdatasource.annotation.DataSource;
import com.jyy.utils.dynamicdatasource.DynamicBaseQuery;
import com.jyy.utils.dynamicdatasource.DynamicContextHolder;
import com.jyy.utils.dynamicdatasource.config.DynamicDataSource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDate;
import java.util.regex.Pattern;

/**
 * 多数据源，切面处理类
 *
 * @author jyy
 * @data 2025-01-14
 */
@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
@RequiredArgsConstructor
public class DataSourceAspect {

    private final DynamicProperties dynamicProperties;

    private static final Pattern YEAR_PATTERN = Pattern.compile("^\\d{4}$");

    /**
     * 定义切点
     * {@code @annotation(com.jyy.dynamicdatasource.annotation.DataSource)}： 如果方法上有com.jyy.dynamicdatasource.DataSource注解，那么这个方法就会被拦截。
     * {@code @within(com.jyy.dynamicdatasource.annotation.DataSource}： 如果方法所在的类上有com.jyy.dynamicdatasource.DataSource注解，那么这个方法也会被拦截。
     */
    @Pointcut("@annotation(com.jyy.utils.dynamicdatasource.annotation.DataSource) || @within(com.jyy.utils.dynamicdatasource.annotation.DataSource)")
    public void dataSourcePointCut() {

    }

    /**
     * 环绕通知
     * {@code @Around("dataSourcePointCut()")}： 这个环绕通知将应用于定义在dataSourcePointCut()中的方法
     *
     * @param point ProceedingJoinPoint对象可以获取方法签名和目标类
     * @return 方法
     * @throws Throwable 抛出异常
     */
    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 获取方法信息
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 获取目标方法
        Method method = signature.getMethod();

        // 获取方法参数名称数组
        String[] parameterNames = signature.getParameterNames();
        // 获取方法参数值数组
        Object[] args = point.getArgs();

        // 用于存储startYearFlag参数的值
        String startYearFlag = null;

        // 遍历参数，找到名为startYearFlag的参数
        for (int i = 0; i < parameterNames.length; i++) {
            // 假设args[i]是DynamicBaseQuery类型，它继承自DynamicBaseQuery
            if (args[i] instanceof DynamicBaseQuery) {
                DynamicBaseQuery query = (DynamicBaseQuery) args[i];
                // 直接获取startYearFlag属性
                startYearFlag = query.getStartYearFlag();
                break;
            }
        }

        // 当前年份
        String year = String.valueOf(LocalDate.now().getYear());

        // 如果找到了startYearFlag参数，则使用它的值
        String value;
        if (isValidYear(startYearFlag)) {
            value = startYearFlag;
        } else {
            // 如果没有找到，保持原来的逻辑
            // 获取目标类上的注解
            DataSource targetDataSource = (DataSource) point.getTarget().getClass().getAnnotation(DataSource.class);
            // 获取方法上的注解
            DataSource methodDataSource = method.getAnnotation(DataSource.class);
            if (null != methodDataSource && StringUtils.isNotEmpty(methodDataSource.value())) {
                value = methodDataSource.value();
            } else if (null != targetDataSource && StringUtils.isNotEmpty(targetDataSource.value())) {
                value = targetDataSource.value();
            } else {
                // 当前年份
                value = year;
            }
        }

        // 判断获取的年份是否大于当前年份
        if (Integer.parseInt(value) > Integer.parseInt(year)) {
            log.error("{}{} 数据源不存在，使用当前{}年份数据源", DynamicConstant.SQLSERVER_PREFIX, value, year);
            value = year;
        } else if (Integer.parseInt(value) < 2023) {
            log.error("{}{} 数据源不存在，使用当前{}年份数据源", DynamicConstant.SQLSERVER_PREFIX, value, year);
            value = year;
        }

        // 根据dbKey动态设置数据源
        String dataBaseName = DynamicConstant.SQLSERVER_PREFIX + value;
        DynamicDataSource.setDataSource(dataBaseName, dynamicProperties);
        log.debug("设置数据源为： {}", dataBaseName);

        try {
            // 执行方法
            return point.proceed();
        } finally {
            DynamicContextHolder.poll();
            log.debug("clean datasource");
        }
    }

    /**
     * 校验字符串是否是年份
     *
     * @param year 年份字符串
     * @return true 是年份，false 不是年份
     */
    public static boolean isValidYear(String year) {
        if (StringUtils.isEmpty(year)) {
            return false;
        }
        return YEAR_PATTERN.matcher(year).matches();
    }
}
